package cyb;

import org.tinspin.index.kdtree.KDIterator;
import org.tinspin.index.kdtree.KDTree;
import org.tinspin.index.kdtree.Node;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.*;


public class JoinBase {

    public static List<String> gen2Co(List<String> typePoiList1, List<String> typePoiList2, Map<String, POI> poiMap,
                                      Map<String, List<String>> oneCoMap, String type1, String type2) {
        Set type1Set = new HashSet();
        Set type2Set = new HashSet();
        List<Integer> two_co_typeNumList = new LinkedList<>();
        //1.产生候选2阶特征表实例
        List<String> coList = new LinkedList<>();
        for (String typePoi1 : typePoiList1) {
            for (String typePoi2 : typePoiList2) {
                POI poi11 = poiMap.get(typePoi1);
                POI poi22 = poiMap.get(typePoi2);
                if (Util.getDistance(poi11.getX(), poi11.getY(), poi22.getX(), poi22.getY()) <= Properties.R) {
                    String two_co = typePoi1 + "," + typePoi2;
                    coList.add(two_co);
                    type1Set.add(typePoi1);
                    type2Set.add(typePoi2);
                }
            }
        }
        if (type1Set.size() == 0) {
            return null;
        }
        double type1Support = Util.int2double(type1Set.size()) / oneCoMap.get(type1).size();
        double type2Support = Util.int2double(type2Set.size()) / oneCoMap.get(type2).size();
        double twoCo_Support = Math.min(type1Support, type2Support);
        if (twoCo_Support < Properties.support) {
            return null;
        }
        return coList;
    }

    public static Map<String, List<String>> genAll2Co(Map<String, POI> poiMap, Map<String, List<String>> oneCoMap) {
        int cutNum = 0;
        Map<String, List<String>> twoCoMap = new HashMap<>();
        for (Map.Entry<String, List<String>> entry1 : oneCoMap.entrySet()) {
            String type1 = entry1.getKey();
            List<String> typePoiList1 = entry1.getValue();

            for (Map.Entry<String, List<String>> entry2 : oneCoMap.entrySet()) {
                String type2 = entry2.getKey();
                if (Integer.valueOf(type1) < Integer.valueOf(type2)) {
                    List<String> typePoiList2 = entry2.getValue();
                    List<String> two_Co = gen2Co(typePoiList1, typePoiList2, poiMap, oneCoMap, type1, type2);
                    if (two_Co != null) {
                        twoCoMap.put(type1 + "," + type2, two_Co);//未被剪枝
                    } else {
                        cutNum++;
                    }
                }
            }
        }
        System.out.println("=> 2阶模式剪枝 " + cutNum + " 个");
        return twoCoMap;
    }

    /**
     * 将2个n阶模式合成一个n+1阶模式(n>1)
     *
     * @param coPoiList1   某个n阶co模式1 实例集 (如a1,b1 )
     * @param coPoiList2   某个n阶co模式2 实例集 (如a1,c2)
     * @param poiMap
     * @param oneCoMap     1阶co模式，用于支持度计算 的分母
     * @param nPlusCo_type 预计生成的n+1阶co模式 （如A,B,C） => 注意注意特征是递增的，因为生成n+1时左边的最后一个特征 比 右边的最后一个小。
     *                     记录该模式下所有特征的实例数，typeMap用于支持度计算 的分子
     */
    private static List<String> genNPlusCo(List<String> coPoiList1, List<String> coPoiList2,
                                           Map<String, POI> poiMap, Map<String, List<String>> oneCoMap, String nPlusCo_type) {
        Map<String, Set<String>> typeMap = new HashMap<>();//记录当前n+1阶模式下，各特征 实例集
        String[] co_typeArr = nPlusCo_type.split(",");
        for (int i = 0; i < co_typeArr.length; i++) {
            typeMap.put(co_typeArr[i], new HashSet<>());
        }

        List<Integer> two_co_typeNumList = new LinkedList<>();
        //1.产生候选n+1阶特征表实例
        List<String> coList = new LinkedList<>();
        for (String coPoi1 : coPoiList1) {
            int index1 = coPoi1.lastIndexOf(",");
            String pre1 = coPoi1.substring(0, index1), suf1 = coPoi1.substring(index1 + 1);
            for (String coPoi2 : coPoiList2) {
                int index2 = coPoi2.lastIndexOf(",");
                String pre2 = coPoi2.substring(0, index2), suf2 = coPoi2.substring(index2 + 1);

                if (pre1.equals(pre2)) { //前n-1阶相同
                    POI poi11 = poiMap.get(suf1);
                    POI poi22 = poiMap.get(suf2);
                    if (Util.getDistance(poi11.getX(), poi11.getY(), poi22.getX(), poi22.getY()) <= Properties.R) {
                        String n_co = pre1 + "," + suf1 + "," + suf2;
                        coList.add(n_co);

                        String[] co_Arr = n_co.split(",");
                        for (int i = 0; i < co_typeArr.length; i++) {
                            String type = co_typeArr[i];
                            String obj = co_Arr[i];
                            typeMap.get(type).add(obj);
                        }
                    }
                }
            }
        }
        if (typeMap.get(co_typeArr[0]).size() == 0) {
            return null;
        }

        double minCoSupport = 2;
        for (Map.Entry<String, Set<String>> entry : typeMap.entrySet()) {
            String type = entry.getKey();
            double tempSupport = Util.int2double(typeMap.get(type).size()) / oneCoMap.get(type).size();
            if (tempSupport < minCoSupport) {
                minCoSupport = tempSupport;
            }
        }
        if (minCoSupport < Properties.support) {
            return null;
        }
        return coList;
    }

    /**
     * 根据所有n阶模式 生成 所有n+1阶模式(n>1)
     *
     * @param nCoMap   （key n阶模式 ：value 对应模式的表实例）
     * @param poiMap
     * @param oneCoMap
     */
    public static Map<String, List<String>> genAllNPlusCo(Map<String, List<String>> nCoMap, Map<String, POI> poiMap,
                                                          Map<String, List<String>> oneCoMap) {
        int cutNum = 0;
        int jie = 0;
        Map<String, List<String>> nPlusCoMap = new HashMap<>();
        for (Map.Entry<String, List<String>> entry1 : nCoMap.entrySet()) {
            String nCo_type1 = entry1.getKey();
            if (jie == 0) jie = nCo_type1.split(",").length + 1;
            int index1 = nCo_type1.lastIndexOf(",");
            String pre1 = nCo_type1.substring(0, index1), suf1 = nCo_type1.substring(index1 + 1);

            for (Map.Entry<String, List<String>> entry2 : nCoMap.entrySet()) {
                String nCo_type2 = entry2.getKey();
                int index2 = nCo_type2.lastIndexOf(",");
                String pre2 = nCo_type2.substring(0, index2), suf2 = nCo_type2.substring(index2 + 1);

                if (pre1.equals(pre2) && (Integer.parseInt(suf1) < Integer.parseInt(suf2))) { //前n-1阶相同,最后一个特征 左边比右边小
                    List<String> typePoiList1 = entry1.getValue();
                    List<String> typePoiList2 = entry2.getValue();
                    String nPlusCo_Type = nCo_type1 + "," + suf2;
                    List<String> nPlusCo = genNPlusCo(typePoiList1, typePoiList2, poiMap, oneCoMap, nPlusCo_Type);

                    if (nPlusCo != null) {
                        nPlusCoMap.put(nPlusCo_Type, nPlusCo);//未被剪枝
                    } else {
                        cutNum++;
                    }
                }
            }
        }
        System.out.println("=> " + jie + "阶模式剪枝 " + cutNum + " 个");

        if (nPlusCoMap.size() == 0) {
            System.out.println("==========================保存JoinBase算法结果==========================");
            try (BufferedWriter bw = new BufferedWriter(new FileWriter(CoLocation.resultPath))) {
                bw.write(nCoMap.toString());
                bw.newLine(); //换行用

            } catch (Exception e) {
                System.out.println("保存结果 数据异常！！！");
                e.printStackTrace();
            }
        }
        return nPlusCoMap;
    }

}
